/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package dbcontrollers;

import dbbeans.Fields;
import dbbeans.Nodes;
import dbbeans.Trees;
import dbbeans.Users;
import dbcontrollers.exceptions.AlreadyExistentUserException;
import dbcontrollers.exceptions.NonexistentEntityException;
import dbcontrollers.exceptions.RollbackFailureException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.transaction.UserTransaction;
import umat.beans.Node;
import umat.beans.Tree;

/**
 *
 * @author Laur
 */
public class MainController {

    private static MainController singleton; // main controller singleton 
    private UsersJpaController usersController; // controller for users bean
    private TreesJpaController treesController; // controller for trees bean
    private NodesJpaController nodesController; // controller for nodes bean
    private FieldsJpaController fieldsController; // controller for fields bean
    private Context ctx; // context used to obtain the transaction instance
    private UserTransaction utx; // user transaction will be sent as a parameter to each bean controller constructor
    private EntityManager em; // entity manager used to obtain a instance of EntityManagerFactory
    private EntityManagerFactory emf; // entity manager factory will be also sent as a parameter to each bean controller constructor
    public final static int FIELD_TYPE_INT = 0; // constant representing type int for a field
    public final static int FIELD_TYPE_DOUBLE = 1; // constant representing type double for a field
    public final static int FIELD_TYPE_STRING = 2; // constant representing type string for a field
    public final static int FIELD_TYPE_BINARY = 3; // constant representing type binary for a field
    public final static int FIELD_TYPE_DATE = 4; // constant representing type date for a field

    private MainController() { // main controller constructor is made private 
        // a new instance will be available outside the class only through getInstance() method
        // who returns the singleton after instantiation if necessary
        try {
            ctx = new InitialContext();  // obtaining the context
            // and the transaction and entity manager. UserTransaction and LogicalName must be declared in web.xml
            utx = (UserTransaction) ctx.lookup("java:comp/env/UserTransaction");
            em = (EntityManager) ctx.lookup("java:comp/env/persistence/LogicalName");
            emf = em.getEntityManagerFactory(); // obtaining an instance of emf
            // Instantiating controllers:
            usersController = new UsersJpaController(utx, emf);
            treesController = new TreesJpaController(utx, emf);
            nodesController = new NodesJpaController(utx, emf);
            fieldsController = new FieldsJpaController(utx, emf);
        } catch (Exception e) {
            Logger.getLogger(getClass().getName()).log(Level.SEVERE, "exception caught", e);
            throw new RuntimeException(e);
        }

    }

    /**
     * method used to obtain a singleton of this class
     *
     * @return
     */
    public static MainController getInstance() {
        if (singleton == null) {
            singleton = new MainController(); // if not already instantiated then call constructor
        }
        return singleton; // return the instance
    }

    /**
     * used to add a new user. Be careful, for registry there is a different
     * method written which also tests if the user exists and throws an
     * exception if the user cannot be registered.
     *
     * @param user
     * @param password
     * @param layout
     */
    public void addUser(String user, String password, int layout) {
        try {
            usersController.create(new Users(0, user, password, layout));
        } catch (RollbackFailureException ex) {
            Logger.getLogger(MainController.class.getName()).log(Level.SEVERE, null, ex);
        } catch (Exception ex) {
            Logger.getLogger(MainController.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Tests if a user exists and register the user if not if the user already
     * exists throws a AlreadyExistentUserException
     *
     * @param user
     * @param password
     * @param layout
     */
    public void registerUser(String user, String password, int layout) throws AlreadyExistentUserException {
        if (usersController.getUserByUser(user) == null) {
            addUser(user, password, layout);

        } else {
            throw new AlreadyExistentUserException();
        }
    }

    /**
     * Method used for login. Returns true if user and password are correct and
     * false contrary
     *
     * @param user
     * @param password
     * @return
     */
    public boolean loginUser(String user, String password) {
        Users u = usersController.getUserByUser(user);
        if (u != null) {
            if (u.getPassword().equals(password)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Method used to add a new tree
     */
    public void addTree(String name, int user) {
        try {
            treesController.create(new Trees(0, name, user));
        } catch (RollbackFailureException ex) {
            Logger.getLogger(MainController.class.getName()).log(Level.SEVERE, null, ex);
        } catch (Exception ex) {
            Logger.getLogger(MainController.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Method used to add a new Node
     *
     * @param name
     * @param value
     * @param parent
     * @param tree
     */
    public void addNode(String name, String value, int parent, int tree) {
        try {
            nodesController.create(new Nodes(0, name, value, parent, tree));
        } catch (RollbackFailureException ex) {
            Logger.getLogger(MainController.class.getName()).log(Level.SEVERE, null, ex);
        } catch (Exception ex) {
            Logger.getLogger(MainController.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Method used to add a new Field
     *
     * @param name
     * @param value
     * @param type
     * @param node
     */
    public void addField(String name, String value, int type, int node) {
        try {
            fieldsController.create(new Fields(0, name, value, type, node));
        } catch (RollbackFailureException ex) {
            Logger.getLogger(MainController.class.getName()).log(Level.SEVERE, null, ex);
        } catch (Exception ex) {
            Logger.getLogger(MainController.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void setLayout(int id, int layout) {
        try {
            Users u = usersController.findUsers(id);
            u.setLayout(layout);
            usersController.edit(u);
        } catch (NonexistentEntityException ex) {
            Logger.getLogger(MainController.class.getName()).log(Level.SEVERE, null, ex);
        } catch (RollbackFailureException ex) {
            Logger.getLogger(MainController.class.getName()).log(Level.SEVERE, null, ex);
        } catch (Exception ex) {
            Logger.getLogger(MainController.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public Users getUserByUser(String user) {
        return usersController.getUserByUser(user);
    }

    public void addTree(Tree tree) {
        String name=tree.getRoot().getData().toString();
        try {
            treesController.create(new Trees(name, 0));
            
        } catch (Exception exc) {
            exc.printStackTrace();
        }
    }
}
